package com.hd123.rumba.gwt.widget2.client.fielddef;

import com.hd123.gwt.types.JsBigDecimal;

/**
 * JsBigDecimal类型字段的定义
 * 
 * @author LiQi
 * 
 */
public class JsBigDecimalFieldDef extends FieldDef {

  /**
   * 最小值，实际值应>=或>最小值（>=还是>由allowEqualsMin决定），为空则使用JsBigDecimal.
   * MINVALUE
   */
  protected JsBigDecimal minValue;

  /** 是否允许等于最小值 */
  protected boolean allowEqualsMin = true;

  /**
   * 最大值，实际值应<=或<最大值（<=还是<由allowEqualsMax决定），为空则使用JsBigDecimal.
   * MAXVALUE
   */
  protected JsBigDecimal maxValue;

  /** 是否允许等于最大值 */
  protected boolean allowEqualsMax = true;

  /** 小数位数，-1表示不限制 */
  protected int scale = -1;

  /** JavaScript中最大精度为15 */
  public static int MAX_PRECISION = 15;

  public JsBigDecimalFieldDef(String name, String caption) {
    super(name, caption, true);
  }

  public JsBigDecimalFieldDef(String name, String caption, boolean nullable, JsBigDecimal minValue,
      boolean allowEqualsMin, JsBigDecimal maxValue, boolean allowEqualsMax, int scale) {
    super(name, caption, nullable);
    this.minValue = minValue == null ? JsBigDecimal.MINVALUE : minValue;
    this.allowEqualsMin = allowEqualsMin;
    this.maxValue = maxValue == null ? JsBigDecimal.MAXVALUE : maxValue;
    this.allowEqualsMax = allowEqualsMax;
    this.scale = scale;
  }

  public FieldDef clone() {
    return new JsBigDecimalFieldDef(name, caption, nullable, minValue, allowEqualsMin, maxValue,
        allowEqualsMax, scale);
  }

  public boolean validateText(String text, StringBuffer message) {
    return validateText(text, message, true);
  }

  /**
   * 验证传入的文本是否能合法的转换成字段的值。
   * 
   * @param text
   * @return
   */
  public boolean validateText(String text, StringBuffer message, boolean checkNullable) {
    JsBigDecimal value;
    if (text == null || text.trim().equals(""))
      value = null;
    else {
      // 清除千位分隔符
      text = text.replaceAll(",", "");

      // 检查精度
      if (text.length() > MAX_PRECISION) {
        finalizeMessage(message, "不能超过最大精度" + MAX_PRECISION + "位");
        return false;
      }

      try {
        value = new JsBigDecimal(text);
      } catch (NumberFormatException e) {
        finalizeMessage(message, "文本不是合法的数值格式");
        return false;
      }

      // 检查scale
      if (scale != -1 && getScale(value.toString()) > scale) {
        finalizeMessage(message, "不能超过" + scale + "位小数");
        return false;
      }
    }

    return validate(value, message, checkNullable);
  }

  /**
   * 计算文本代表的数值的小数位数<br>
   * 去除小数部分最后的0之后的长度，例如0.300的scale就是1
   * 
   * @param text
   * @return
   */
  private int getScale(String text) {
    String[] split = text.split("\\.");
    if (split.length < 2)
      return 0;
    else {
      // 计算去除小数部分最后的0之后的长度
      String s = split[1];
      String[] s2 = s.split("E"); // 如果是科学计数法
      int scientificDigits = 0;
      if (s2.length > 1) {
        scientificDigits = Integer.parseInt(s2[1]);
        s = s2[0];
      }
      int len = s.length();
      while (len > 0 && s.charAt(len - 1) == '0')
        len--;
      return len >= scientificDigits ? len - scientificDigits : 0;
    }
  }

  public boolean validate(JsBigDecimal value, StringBuffer message) {
    return validate(value, message, true);
  }

  /**
   * 验证传入的值是否合法
   * 
   * @param value
   * @return
   */
  public boolean validate(JsBigDecimal value, StringBuffer message, boolean checkNullable) {
    boolean result = super.validate(value, message, checkNullable);
    if (value == null)
      return result;

    // minValue
    if (minValue != null
        && (value.compareTo(minValue) < 0 || (!allowEqualsMin && value.equals(minValue)))) {
      appendMessage(message, "应该大于" + (allowEqualsMin ? "等于" : "") + minValue);
      result = false;
    }

    // maxValue
    if (maxValue != null
        && (value.compareTo(maxValue) > 0 || (!allowEqualsMax && value.equals(maxValue)))) {
      appendMessage(message, "应该小于" + (allowEqualsMax ? "等于" : "") + maxValue);
      result = false;
    }

    finalizeMessage(message);
    return result;
  }

  public boolean validate(Double value, StringBuffer message) {
    return validate(value, message, true);
  }

  public boolean validate(Double value, StringBuffer message, boolean checkNullable) {
    return validate(new JsBigDecimal(value.doubleValue()), message, checkNullable);
  }

  public boolean validate(double value, StringBuffer message) {
    return validate(value, message, true);
  }

  public boolean validate(double value, StringBuffer message, boolean checkNullable) {
    return validate(new JsBigDecimal(value), message, checkNullable);
  }

  public JsBigDecimal getMinValue() {
    return minValue;
  }

  public void setMinValue(JsBigDecimal minValue) {
    this.minValue = minValue;
  }

  public JsBigDecimal getMaxValue() {
    return maxValue;
  }

  public void setMaxValue(JsBigDecimal maxValue) {
    this.maxValue = maxValue;
  }

  public int getScale() {
    return scale;
  }

  public void setScale(int scale) {
    this.scale = scale;
  }

  public boolean isAllowEqualsMin() {
    return allowEqualsMin;
  }

  public void setAllowEqualsMin(boolean allowEqualsMin) {
    this.allowEqualsMin = allowEqualsMin;
  }

  public boolean isAllowEqualsMax() {
    return allowEqualsMax;
  }

  public void setAllowEqualsMax(boolean allowEqualsMax) {
    this.allowEqualsMax = allowEqualsMax;
  }
}
